<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />

    

    
    <title>react中key的正确使用方式 | 李世奇的技术专栏</title>
    
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
        <meta name="keywords" content="React" />
    
    <meta name="description" content="在开发react程序时我们经常会遇到这样的警告，然后就会想到：哦！循环子组件忘记加key了～ 出于方便，有时候会不假思索的使用循环的索引作为key，但是这样真的好吗？什么样的值才是key的最佳选择？ 为了弄明白，本文将从三个方面来分析”key”： 1.为什么要使用key 2.使用index做key存在的问题 3.正确的选择key 1.为什么要使用keyreact官方文档是这样描述key的：">
<meta name="keywords" content="React">
<meta property="og:type" content="article">
<meta property="og:title" content="react中key的正确使用方式">
<meta property="og:url" content="https://www.lisq.xyz/2018/11/27/【React深入】react中key的正确使用方式/index.html">
<meta property="og:site_name" content="李世奇的技术专栏">
<meta property="og:description" content="在开发react程序时我们经常会遇到这样的警告，然后就会想到：哦！循环子组件忘记加key了～ 出于方便，有时候会不假思索的使用循环的索引作为key，但是这样真的好吗？什么样的值才是key的最佳选择？ 为了弄明白，本文将从三个方面来分析”key”： 1.为什么要使用key 2.使用index做key存在的问题 3.正确的选择key 1.为什么要使用keyreact官方文档是这样描述key的：">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://www.lisq.xyz/img/5.jpg">
<meta property="og:updated_time" content="2019-04-16T11:42:43.649Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="react中key的正确使用方式">
<meta name="twitter:description" content="在开发react程序时我们经常会遇到这样的警告，然后就会想到：哦！循环子组件忘记加key了～ 出于方便，有时候会不假思索的使用循环的索引作为key，但是这样真的好吗？什么样的值才是key的最佳选择？ 为了弄明白，本文将从三个方面来分析”key”： 1.为什么要使用key 2.使用index做key存在的问题 3.正确的选择key 1.为什么要使用keyreact官方文档是这样描述key的：">
<meta name="twitter:image" content="https://www.lisq.xyz/img/5.jpg">
    

    

    

    <link rel="stylesheet" href="/libs/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/libs/titillium-web/styles.css">
    <link rel="stylesheet" href="/libs/source-code-pro/styles.css">

    <link rel="stylesheet" href="/css/style.css">

    <script src="/libs/jquery/3.3.1/jquery.min.js"></script>
    
    
        <link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css">
    
    
        <link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css">
    
    
    


</head>


<body>
    <div id="wrap">
        <header id="header">
    <div id="header-outer" class="outer">
        <div class="container">
            <div class="container-inner">
                <div id="header-title">
                    <h1 class="logo-wrap">
                        <a href="/" class="logo"></a>
                    </h1>
                    
                </div>
                <div id="header-inner" class="nav-container">
                    <a id="main-nav-toggle" class="nav-icon fa fa-bars"></a>
                    <div class="nav-container-inner">
                        <ul id="main-nav">
                            
                                <li class="main-nav-list-item" >
                                    <a class="main-nav-list-link" href="/">主页</a>
                                </li>
                            
                                        
                                    
                                <li class="main-nav-list-item" >
                                    <a class="main-nav-list-link" href="https://mp.weixin.qq.com/s/dYZEHTgqvxGV7mL99JuxRQ">关于</a>
                                </li>
                            
                                <li class="main-nav-list-item" >
                                    <a class="main-nav-list-link" href="https://github.com/ConardLi/ConardLi.github.io">更新日志</a>
                                </li>
                            
                                <li class="main-nav-list-item" >
                                    <a class="main-nav-list-link" href="/me/navigation.html">index.导航</a>
                                </li>
                            
                        </ul>
                        <nav id="sub-nav">
                            <div id="search-form-wrap">

    <form class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
        <button type="submit" class="search-form-submit"></button>
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="想要查找什么..." />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>

</div>
                        </nav>
                    </div>
                </div>
            </div>
        </div>
    </div>
</header>
        <div class="container">
            <div class="main-body container-inner">
                <div class="main-body-inner">
                    <section id="main">
                        <div class="main-body-header">
    <h1 class="header">
    
    未分类
    </h1>
</div>

                        <div class="main-body-content">
                            <style>
    #article-toc.fixed {
        position: fixed;
        top: 30px;
        bottom: 30px;
        left: 32px;
        padding-top: 15px;
        z-index: 9999;
        background-color: antiquewhite;
        width: 200px;
        padding-left: 20px;
        padding-bottom: 30px;
        border-radius: 10px;
        border: 1px solid rgb(122, 122, 122);
        opacity: 0.8;
    }

    #article-toc-inner {
        padding: 10px;
        width: 200px;
        height: 100%;
        overflow: auto;
    }

    .toc-level-3 {
        margin-left: 20px;
    }

    #article-toc a {
        text-decoration: none;
        color: #333;
        padding: 3px 0;
        color: #000;
        font-weight: normal;
    }

    .toc-item {
        line-height: 30px;
        list-style-type: initial;
    }

    #tocbtn {
        position: fixed;
        top: 30%;
        left: 0px;
        padding: 5px 2px;
        width: 18px;
        word-wrap: break-word;
        background-color: rgb(242, 245, 247);
        box-shadow: rgba(118, 118, 118, 0.11) 2px 0px 5px 0px;
        opacity: 1;
        height: 94px;
        line-height: 16px;
        text-align: center;
        top: 33%;
        width: 30px;
        z-index: 1000000001;
        cursor: pointer;
        border-radius: 0px 4px 4px 0px;
        border-width: 1px 1px 1px;
        border-style: solid solid solid none;
        border-color: rgb(224, 228, 231) rgb(224, 228, 231) rgb(224, 228, 231);
        border-image: initial;
        border-left: none;
        padding: 6px;
        transition: right 0.4s ease-in 0.3s, opacity 0.5s ease-in 0.3s;
    }
</style>

<article id="post-【React深入】react中key的正确使用方式"
    class="article article-single article-type-post"
    itemscope itemprop="blogPost">
    <div class="article-inner">
        
        <header class="article-header">
            
    
        <h1 class="article-title" itemprop="name">
        react中key的正确使用方式
        </h1>
    

        </header>
        
        
        <div class="article-meta">
            
    <div class="article-date">
        <a href="/2018/11/27/【React深入】react中key的正确使用方式/" class="article-date">
            <time datetime="2018-11-26T17:50:45.000Z" itemprop="datePublished">2018-11-27</time>
        </a>
    </div>

            

            
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/React/">React</a>
    </div>

            <span id="busuanzi_container_page_pv" style="position: relative;float: right;">
                本文总阅读量<span id="busuanzi_value_page_pv"></span>次
            </span>
        </div>
        
        
        <div class="article-entry" itemprop="articleBody">
            <p><img src="https://www.lisq.xyz/img/5.jpg" alt="image"></p>
<p><img src="https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/key1.png" alt="image"></p>
<p>在开发react程序时我们经常会遇到这样的警告，然后就会想到：哦！循环子组件忘记加key了～</p>
<p>出于方便，有时候会不假思索的使用循环的索引作为key，但是这样真的好吗？什么样的值才是key的最佳选择？</p>
<p>为了弄明白，本文将从三个方面来分析”key”：</p>
<p>1.为什么要使用key</p>
<p>2.使用index做key存在的问题</p>
<p>3.正确的选择key</p>
<h1 id="1-为什么要使用key"><a href="#1-为什么要使用key" class="headerlink" title="1.为什么要使用key"></a>1.为什么要使用key</h1><p>react官方文档是这样描述key的：</p>
<blockquote>
<p>Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。</p>
</blockquote>
<p>react的diff算法是把key当成唯一id然后比对组件的value来确定是否需要更新的，所以如果没有key，react将不会知道该如何更新组件。</p>
<p>你不传key也能用是因为react检测到子组件没有key后，会默认将数组的索引作为key。</p>
<p>react根据key来决定是销毁重新创建组件还是更新组件，原则是：</p>
<ul>
<li>key相同，组件有所变化，react会只更新组件对应变化的属性。</li>
<li>key不同，组件会销毁之前的组件，将整个组件重新渲染。</li>
</ul>
<h1 id="2-使用index做key存在的问题"><a href="#2-使用index做key存在的问题" class="headerlink" title="2.使用index做key存在的问题"></a>2.使用index做key存在的问题</h1><h2 id="2-1-受控组件"><a href="#2-1-受控组件" class="headerlink" title="2.1 受控组件"></a>2.1 受控组件</h2><p>单纯的展示组件比如span，这些组件是受控组件，意味着他们的值将是我们给定好的。</p>
<p>如果子组件只是受控组件，使用index作为key，可能表面上不会有什么问题，实际上性能会受很大的影响。例如下面的代码：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">// ['张三','李四','王五']=&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">// 数组重排 -&gt; ['王五','张三','李四'] =&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>当元素数据源的顺序发生改变时，对应的：</p>
<p>key为0，1，2的组件都发生了变化，三个子组件都会被重新渲染。（这里的重新渲染不是销毁，因为key还在）</p>
<p>相反，我们使用唯一id作为key：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">// ['张三','李四','王五']=&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"000"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"111"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"222"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">// 数组重排 -&gt; ['王五','张三','李四'] =&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"222"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"000"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"111"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>根据上面的更新原则，子组件的值和key均未发生变化，只是顺序发生改变，因此react只是将他们做了移动，并未重新渲染。</p>
<h2 id="2-2-非受控组件"><a href="#2-2-非受控组件" class="headerlink" title="2.2 非受控组件"></a>2.2 非受控组件</h2><p>像input这样可以由用户任意改变值，不受我们控制的组件，在使用了index作为key时可能会发生问题，看如下的栗子：</p>
<p>子组件：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">  render() &#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">      &lt;div&gt;</span><br><span class="line">        &lt;p &gt;值：&#123;<span class="keyword">this</span>.props.value&#125;&lt;<span class="regexp">/p&gt;</span></span><br><span class="line"><span class="regexp">        &lt;input /</span>&gt;</span><br><span class="line">      &lt;<span class="regexp">/div&gt;</span></span><br><span class="line"><span class="regexp">    );</span></span><br><span class="line"><span class="regexp">  &#125;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br></pre></td></tr></table></figure>
<p>父组件<br><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line"><span class="keyword">this</span>.state.data.map(<span class="function">(<span class="params">element, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">Child</span> <span class="attr">value</span>=<span class="string">&#123;element&#125;</span> <span class="attr">key</span>=<span class="string">&#123;index&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="xml">    &#125;)</span></span><br><span class="line"><span class="xml">&#125;</span></span><br></pre></td></tr></table></figure></p>
<p>我们在前两个输入框分别输入对应的值：</p>
<p><img src="https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/key2.png" alt="image"></p>
<p>然后在头部添加一个元素：</p>
<p><img src="https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/key3.png" alt="image"></p>
<p>很明显，这个结果并不符合我们的预期，我们来分析一下发生了什么：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：0<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：2<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>变化后：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：5<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：0<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"3"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：2<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>可以发现：key 0，1，2并没有发生改变，根据规则，不会卸载组件，只会更新改变的属性。</p>
<p>react只diff到了p标签内值的变化，而input框中的值并未发生改变，因此不会重新渲染，只更新的p标签的值。</p>
<p>当使用唯一id作为key后：</p>
<p><img src="https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/key5.png" alt="image"></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"000"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：0<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"111"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"222"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：2<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>变化后：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"555"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：5<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"000"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：0<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"111"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">"222"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> &gt;</span>值：2<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>可以很明显的发现：key为 111，222，333的组件没有发生任何改变，react不会更新他们，只是新插入了子组件555，并改变了其他组件的位置。</p>
<h1 id="3-正确的选择key"><a href="#3-正确的选择key" class="headerlink" title="3.正确的选择key"></a>3.正确的选择key</h1><h2 id="3-1-纯展示"><a href="#3-1-纯展示" class="headerlink" title="3.1 纯展示"></a>3.1 纯展示</h2><p>如果组件单纯的用于展示，不会发生其他变更，那么使用index或者其他任何不相同的值作为key是没有任何问题的，因为不会发生diff，就不会用到key。</p>
<h2 id="3-2-推荐使用index的情况"><a href="#3-2-推荐使用index的情况" class="headerlink" title="3.2 推荐使用index的情况"></a>3.2 推荐使用index的情况</h2><p>并不是任何情况使用index作为key会有缺陷，比如如下情况：</p>
<p>你要分页渲染一个列表，每次点击翻页会重新渲染：</p>
<p>使用唯一id：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">第一页</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"000"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"111"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"222"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">第二页</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"333"</span>&gt;</span>张三三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"444"</span>&gt;</span>李四四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"555"</span>&gt;</span>王五五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>翻页后，三条记录的key和组件都发生了改变，因此三个子组件都会被卸载然后重新渲染。</p>
<p>使用index：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">第一页</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span>张三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span>李四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">第二页</span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"0"</span>&gt;</span>张三三<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"1"</span>&gt;</span>李四四<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">key</span>=<span class="string">"2"</span>&gt;</span>王五五<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>翻页后，key不变，子组件值发生改变，组件并不会被卸载，只发生更新。</p>
<h2 id="3-3-子组件可能发生变更-使用了非受控组件"><a href="#3-3-子组件可能发生变更-使用了非受控组件" class="headerlink" title="3.3 子组件可能发生变更/使用了非受控组件"></a>3.3 子组件可能发生变更/使用了非受控组件</h2><p>大多数情况下，使用唯一id作为子组件的key是不会有任何问题的。</p>
<p>这个id一定要是唯一，并且稳定的，意思是这条记录对应的id一定是独一无二的，并且永远不会发生改变。</p>
<p>不推荐使用math.random或者其他的第三方库来生成唯一值作为key。</p>
<p>因为当数据变更后，相同的数据的key也有可能会发生变化，从而重新渲染，引起不必要的性能浪费。</p>
<p>如果数据源不满足我们这样的需求，我们可以在渲染之前为数据源手动添加唯一id，而不是在渲染时添加。</p>

        </div>
        <footer class="article-footer">
            



    <a data-url="https://www.lisq.xyz/2018/11/27/【React深入】react中key的正确使用方式/" data-id="cjv0hxjy70004nh0dae5d27g6" class="article-share-link"><i class="fa fa-share"></i>分享到</a>
<script>
    (function ($) {
        $('body').on('click', function() {
            $('.article-share-box.on').removeClass('on');
        }).on('click', '.article-share-link', function(e) {
            e.stopPropagation();

            var $this = $(this),
                url = $this.attr('data-url'),
                encodedUrl = encodeURIComponent(url),
                id = 'article-share-box-' + $this.attr('data-id'),
                offset = $this.offset(),
                box;

            if ($('#' + id).length) {
                box = $('#' + id);

                if (box.hasClass('on')){
                    box.removeClass('on');
                    return;
                }
            } else {
                var html = [
                    '<div id="' + id + '" class="article-share-box">',
                        '<input class="article-share-input" value="' + url + '">',
                        '<div class="article-share-links">',
                            '<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="article-share-twitter" target="_blank" title="Twitter"></a>',
                            '<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="article-share-facebook" target="_blank" title="Facebook"></a>',
                            '<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="article-share-pinterest" target="_blank" title="Pinterest"></a>',
                            '<a href="https://plus.google.com/share?url=' + encodedUrl + '" class="article-share-google" target="_blank" title="Google+"></a>',
                        '</div>',
                    '</div>'
                ].join('');

              box = $(html);

              $('body').append(box);
            }

            $('.article-share-box.on').hide();

            box.css({
                top: offset.top + 25,
                left: offset.left
            }).addClass('on');

        }).on('click', '.article-share-box', function (e) {
            e.stopPropagation();
        }).on('click', '.article-share-box-input', function () {
            $(this).select();
        }).on('click', '.article-share-box-link', function (e) {
            e.preventDefault();
            e.stopPropagation();

            window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450');
        });
    })(jQuery);
</script>

        </footer>
    </div>
</article>


    <section id="comments">
    
        
    <div id="disqus_thread">
        <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    </div>

    
    </section>





<div id="roott"></div>

<button id="tocbtn">打开目录</button>


<script>
    var showToc = false;
    document.getElementById('tocbtn').onclick = function () {
        if (showToc) {
            document.getElementById('roott').innerHTML = ''
            document.getElementById('tocbtn').innerHTML = '打开目录'
        } else {
            document.getElementById('roott').innerHTML = `<aside id="article-toc" role="navigation" class="fixed">
  <div id="article-toc-inner">
    <strong class="sidebar-title">
      目录</strong>
    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-为什么要使用key"><span class="toc-text">1.为什么要使用key</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-使用index做key存在的问题"><span class="toc-text">2.使用index做key存在的问题</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-受控组件"><span class="toc-text">2.1 受控组件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-非受控组件"><span class="toc-text">2.2 非受控组件</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-正确的选择key"><span class="toc-text">3.正确的选择key</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-1-纯展示"><span class="toc-text">3.1 纯展示</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-推荐使用index的情况"><span class="toc-text">3.2 推荐使用index的情况</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-子组件可能发生变更-使用了非受控组件"><span class="toc-text">3.3 子组件可能发生变更/使用了非受控组件</span></a></li></ol></li></ol>
  </div>
</aside>`
            document.getElementById('tocbtn').innerHTML = '关闭目录'
        }
        showToc = !showToc;
    }
</script>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src='//unpkg.com/valine/dist/Valine.min.js'></script>
<div id="vcomments" style="padding: 30px;"></div>
<script>
    new Valine({
        el: '#vcomments',
        appId: 's1xL54gwvPRsIy3ciItiPhyD-gzGzoHsz',
        appKey: 'CmP8stKpHUHtp5abbTxpqc4H'
    })
</script>
                        </div>
                    </section>
                    <aside id="sidebar">
    <a class="sidebar-toggle" title="Expand Sidebar"><i class="toggle icon"></i></a>
    <div class="sidebar-top">
        <p>
            关注我 :</p>
        <ul class="social-links">
            
            
            <li>
                <a class="social-tooltip" title="github" href="https://github.com/ConardLi"
                    target="_blank" rel="noopener">
                    <i class="icon fa fa-github"></i>
                </a>
            </li>
            
            
        </ul>
    </div>
    
    
<nav id="article-nav">
    
        <a href="/2018/12/17/【electron】指令控制-windows-电源选项/" id="article-nav-newer" class="article-nav-link-wrap">
        <strong class="article-nav-caption">下一篇</strong>
        <p class="article-nav-title">
        
            指令控制 windows 电源选项
        
        </p>
        <i class="icon fa fa-chevron-right" id="icon-chevron-right"></i>
    </a>
    
    
        <a href="/2018/11/07/【electron】electron程序保护措施（崩溃监控，开机自启，托盘关闭）/" id="article-nav-older" class="article-nav-link-wrap">
        <strong class="article-nav-caption">上一篇</strong>
        <p class="article-nav-title">electron程序保护措施（崩溃监控，开机自启，托盘关闭）</p>
        <i class="icon fa fa-chevron-left" id="icon-chevron-left"></i>
        </a>
    
</nav>

    
    <div class="widgets-container" style="background-color: #fff; border-right: 1px solid #e2e2e2;">
        
        
        
<div class="widget-wrap widget-list">
    <h3 class="widget-title">
        微信公众号
    </h3>
    <div class="widget">
        <img src="https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/gzh/qrcode.jpg" alt="">
    </div>
</div>

        
        

        
        
    <div class="widget-wrap">
        <h3 class="widget-title">最新文章</h3>
        <div class="widget">
            <ul id="recent-post" class="">
                
                    <li>
                        
                        <div class="item-thumbnail">
                            <a href="/2019/04/26/【自检】前端知识清单/" class="thumbnail">
    
    
        <span style="background-image:url(https://lsqimg-1257917459.cos.ap-beijing.myqcloud.com/blog/知识体系.png)" alt="【自检】前端知识清单" class="thumbnail-image"></span>
    
    
</a>

                        </div>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2019/04/26/【自检】前端知识清单/" class="title">【自检】前端知识清单</a></p>
                            <p class="item-date"><time datetime="2019-04-26T01:11:22.000Z" itemprop="datePublished">2019-04-26</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-thumbnail">
                            <a href="/2019/04/17/【React深入】深入分析虚拟DOM的渲染原理和特性/" class="thumbnail">
    
    
        <span style="background-image:url(https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/blog/react11.png)" alt="【React深入】深入分析虚拟DOM的渲染原理和特性" class="thumbnail-image"></span>
    
    
</a>

                        </div>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2019/04/17/【React深入】深入分析虚拟DOM的渲染原理和特性/" class="title">【React深入】深入分析虚拟DOM的渲染原理和特性</a></p>
                            <p class="item-date"><time datetime="2019-04-17T03:15:27.000Z" itemprop="datePublished">2019-04-17</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-thumbnail">
                            <a href="/2019/04/09/【React深入】从Mixin到HOC再到Hook/" class="thumbnail">
    
    
        <span style="background-image:url(https://lsqimg-1257917459.cos-website.ap-beijing.myqcloud.com/blog/hoc9.png)" alt="【React深入】从Mixin到HOC再到Hook" class="thumbnail-image"></span>
    
    
</a>

                        </div>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2019/04/09/【React深入】从Mixin到HOC再到Hook/" class="title">【React深入】从Mixin到HOC再到Hook</a></p>
                            <p class="item-date"><time datetime="2019-04-09T15:27:27.000Z" itemprop="datePublished">2019-04-09</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-thumbnail">
                            <a href="/2019/03/28/【浏览器和网络】全面分析前端的网络请求方式/" class="thumbnail">
    
    
        <span style="background-image:url(/img/network.jpg)" alt="全面分析前端的网络请求方式" class="thumbnail-image"></span>
    
    
</a>

                        </div>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2019/03/28/【浏览器和网络】全面分析前端的网络请求方式/" class="title">全面分析前端的网络请求方式</a></p>
                            <p class="item-date"><time datetime="2019-03-28T12:38:59.000Z" itemprop="datePublished">2019-03-28</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-thumbnail">
                            <a href="/2019/03/12/【前端工程】前端开发者必备的nginx知识/" class="thumbnail">
    
    
        <span style="background-image:url(/img/nginx.jpg)" alt="前端开发者必备的nginx知识" class="thumbnail-image"></span>
    
    
</a>

                        </div>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2019/03/12/【前端工程】前端开发者必备的nginx知识/" class="title">前端开发者必备的nginx知识</a></p>
                            <p class="item-date"><time datetime="2019-03-12T06:50:35.000Z" itemprop="datePublished">2019-03-12</time></p>
                        </div>
                    </li>
                
            </ul>
        </div>
    </div>

        
        
<div class="widget-wrap widget-list">
    <div class="">
        <h3 class="widget-title">标签</h3>
        <div class="widget widget-wrap-inn">
            <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/学习提升/">-学习提升</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/JavaScript/">JavaScript</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/React/">React</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/electron/">electron</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/博客搭建/">博客搭建</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/性能优化/">性能优化</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/浏览器和网络/">浏览器和网络</a><span class="tag-list-count">1</span></li></ul>
        </div>
    </div>
</div>


<style>
    .widget-wrap-inn {
        background-color: white;
        padding: 10px;
        border-radius: 5px;
        border: 1px solid #ddd;
    }
</style>
        
        
<div class="widget-wrap widget-list">
    <h3 class="widget-title">归档</h3>
    <div class="widget  widget-wrap-inn">
        <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/04/">四月 2019</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">三月 2019</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">十二月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">十一月 2018</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/01/">一月 2018</a><span class="archive-list-count">1</span></li></ul>
    </div>
</div>

        
        
<div class="widget-wrap widget-list">
    <h3 class="widget-title">友情链接</h3>
    <div class="widget  widget-wrap-inn">
        <ul>
            
            <li>
                <a href="https://juejin.im/user/5bea27965188250edf4ad8b7">掘金</a>
            </li>
            
            <li>
                <a href="https://segmentfault.com/u/conardli">segmentfault</a>
            </li>
            
            <li>
                <a href="https://github.com/ConardLi">github</a>
            </li>
            
            <li>
                <a href="https://github.com/ConardLi/tpanorama">tpanorama</a>
            </li>
            
            <li>
                <a href="http://chuangzaoshi.com/">创造狮导航</a>
            </li>
            
        </ul>
    </div>
</div>

        
        
<div class="widget-wrap widget-list">
    <!-- <h3 class="widget-title">
        腾讯云专属福利
    </h3> -->
    <div class="widget">
        <a target="_blank"
            href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=1a3e7b07487819e129852ba7a4543262&from=console">
            <img src="/img/txy.jpg" id="txy" alt="">
        </a>
    </div>
</div>



<style>
    #txy {
        width: 280px;
        border: 5px;
    }
</style>
        
        
<div class="widget-wrap widget-list">
    <div class="widget">
        <a target="_blank" href="https://promotion.aliyun.com/ntms/act/qwbk.html?userCode=y3kv7eoj">
            <img src="/img/aly.png" id="txy" alt="">
        </a>
    </div>
</div>



<style>
    #txy {
        width: 280px;
        border: 5px;
    }
</style>
        
        
    </div>
</aside>
                </div>
            </div>
        </div>
        <footer id="footer">
    <div class="container">
        <div class="container-inner">
            <a id="back-to-top" href="javascript:;"><i class="icon fa fa-angle-up"></i></a>
            <div class="credit">
                <h1 class="logo-wrap">
                    <a href="/" class="logo"></a>
                </h1>
                <p>&copy;
                    2019
                    ConardLi
                </p>
                <p>Powered by <a href="//hexo.io/" target="_blank">Hexo</a>. Theme by <a href="//github.com/ppoffice"
                        target="_blank">ConardLi</a></p>
                <script type="text/javascript">
                    var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
                    document.write(unescape("%3Cspan id='cnzz_stat_icon_1275088352'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s22.cnzz.com/z_stat.php%3Fid%3D1275088352%26show%3Dpic' type='text/javascript'%3E%3C/script%3E"));
                </script>
                <span id="busuanzi_container_site_pv" style="margin-left:50px;">
                    本站总访问量<span id="busuanzi_value_site_pv"></span>次
                </span>
                <span id="busuanzi_container_site_uv" style="margin-left:50px;">
                    本站访客数<span id="busuanzi_value_site_uv"></span>人次
                </span>
            </div>
            <div class="footer-plugins">
                
    


            </div>
        </div>
    </div>
</footer>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
        
    
    <script>
    var disqus_shortname = 'hexo-theme-hueman';
    
    
    var disqus_url = 'https://www.lisq.xyz/2018/11/27/【React深入】react中key的正确使用方式/';
    
    (function() {
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true;
    dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
    </script>




    
        <script src="/libs/lightgallery/js/lightgallery.min.js"></script>
        <script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script>
        <script src="/libs/lightgallery/js/lg-pager.min.js"></script>
        <script src="/libs/lightgallery/js/lg-autoplay.min.js"></script>
        <script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script>
        <script src="/libs/lightgallery/js/lg-zoom.min.js"></script>
        <script src="/libs/lightgallery/js/lg-hash.min.js"></script>
        <script src="/libs/lightgallery/js/lg-share.min.js"></script>
        <script src="/libs/lightgallery/js/lg-video.min.js"></script>
    
    
        <script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>
    
    



<!-- Custom Scripts -->
<script src="/js/main.js"></script>

    </div>
</body>

</html>